﻿using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace Von.Library
{
    public class VonCrypt
    {
        const string B64Chars = "6XutUOdSRPYpQ5ev1@mhgx7r3DiGk0BnM24a8FLAVlIyjZqf%E9CKzHWcwboGsNT%MmCBNyx1bUP5SZWtI0qrd@sDpoHnu8LT3Re9lkF24EiAvYVfgj7ac6GKzXGQOwhjmCS3bGPI0sXTVFy%8ezk9aAcqnZtDlNKUYwWHiLruMG5xf4@1g2QE7R6opOvdhBfI6X@vP3qikhFgdMmbNOS9Rr%jUsLlDuG7We4ywCEoapYZVHT0xKBc1G5t8AnQ2z";
        public static string MD5File(string filename)
        {
            FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
            string str = MD5Stream(fs);
            fs.Close();
            return str;
        }
        public static string MD5Stream(Stream st)
        {
            MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider();
            byte[] md5byte = MD5.ComputeHash(st);
            string str = "";
            foreach (byte b in md5byte)
            {
                str += B64Chars[b];
            }
            return str;
        }
        public static string MD5String(string text)
        {
            byte[] byts = Encoding.UTF8.GetBytes(text);
            MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider();
            byte[] md5byte = MD5.ComputeHash(byts);
            string str = "";
            foreach (byte b in md5byte)
            {
                str += B64Chars[b];
            }
            return str;
        }
        public enum CryptKind { DES, RC2, AES, Rijndael }
        public static void Encrypt(CryptKind kind, byte[] byKey, Stream inStream, Stream outStream)
        {
            SymmetricAlgorithm sProvider = null;

            if (kind == CryptKind.DES)
                sProvider = new DESCryptoServiceProvider();
            else if (kind == CryptKind.RC2)
                sProvider = new RC2CryptoServiceProvider();
            else if (kind == CryptKind.AES)
                sProvider = new AesCryptoServiceProvider();
            else if (kind == CryptKind.Rijndael)
                sProvider = Rijndael.Create();
            //把密钥转换成字节数组
            byte[] bytesKey = new byte[sProvider.KeySize / 8];
            for (int i = 0; i < bytesKey.Length; i++)
                bytesKey[i] = byKey[i % byKey.Length];
            //把向量转换成字节数组
            byte[] bytesIV = new byte[sProvider.IV.Length];
            for (int i = 0; i < bytesIV.Length; i++)
                bytesIV[i] = byKey[i % byKey.Length];
            CryptoStream cst = new CryptoStream(outStream, sProvider.CreateEncryptor(bytesKey, bytesIV), CryptoStreamMode.Write);
            inStream.Position = 0;
            inStream.CopyTo(cst);
            cst.FlushFinalBlock();
        }
        public static void Encrypt(CryptKind kind, byte[] byKey, byte[] inData, out byte[] outData)
        {
            SymmetricAlgorithm sProvider = null;

            if (kind == CryptKind.DES)
                sProvider = new DESCryptoServiceProvider();
            else if (kind == CryptKind.RC2)
                sProvider = new RC2CryptoServiceProvider();
            else if (kind == CryptKind.AES)
                sProvider = new AesCryptoServiceProvider();
            else if (kind == CryptKind.Rijndael)
                sProvider = Rijndael.Create();
            //把密钥转换成字节数组
            byte[] bytesKey = new byte[sProvider.KeySize / 8];
            for (int i = 0; i < bytesKey.Length; i++)
                bytesKey[i] = byKey[i % byKey.Length];
            //把向量转换成字节数组
            byte[] bytesIV = new byte[sProvider.IV.Length];
            for (int i = 0; i < bytesIV.Length; i++)
                bytesIV[i] = byKey[i % byKey.Length];
            MemoryStream outStream = new MemoryStream();
            CryptoStream cst = new CryptoStream(outStream, sProvider.CreateEncryptor(bytesKey, bytesIV), CryptoStreamMode.Write);
            cst.Write(inData, 0, inData.Length);
            cst.FlushFinalBlock();
            outData = outStream.ToArray();
            outStream.Close();
        }
        public static void Decrypt(CryptKind kind, byte[] byKey, Stream inStream, Stream outStream)
        {
            SymmetricAlgorithm sProvider = null;

            if (kind == CryptKind.DES)
                sProvider = new DESCryptoServiceProvider();
            else if (kind == CryptKind.RC2)
                sProvider = new RC2CryptoServiceProvider();
            else if (kind == CryptKind.AES)
                sProvider = new AesCryptoServiceProvider();
            else if (kind == CryptKind.Rijndael)
                sProvider = Rijndael.Create();
            //把密钥转换成字节数组
            byte[] bytesKey = new byte[sProvider.KeySize / 8];
            for (int i = 0; i < bytesKey.Length; i++)
                bytesKey[i] = byKey[i % byKey.Length];
            //把向量转换成字节数组
            byte[] bytesIV = new byte[sProvider.IV.Length];
            for (int i = 0; i < bytesIV.Length; i++)
                bytesIV[i] = byKey[i % byKey.Length];
            CryptoStream cst = new CryptoStream(outStream, sProvider.CreateDecryptor(bytesKey, bytesIV), CryptoStreamMode.Write);
            inStream.Position = 0;
            inStream.CopyTo(cst);
            cst.FlushFinalBlock();
            //CryptoStream cst;
            //cst = new CryptoStream(inStream, sProvider.CreateDecryptor(bytesDESKey, bytesDESIV), CryptoStreamMode.Write);
            //cst.Position = 0;
            //outStream.Position = 0;
            //cst.CopyTo(outStream);
        }
        public static void Decrypt(CryptKind kind, byte[] byKey, byte[] inData, out byte[] outData)
        {
            SymmetricAlgorithm sProvider = null;

            if (kind == CryptKind.DES)
                sProvider = new DESCryptoServiceProvider();
            else if (kind == CryptKind.RC2)
                sProvider = new RC2CryptoServiceProvider();
            else if (kind == CryptKind.AES)
                sProvider = new AesCryptoServiceProvider();
            else if (kind == CryptKind.Rijndael)
                sProvider = Rijndael.Create();
            //把密钥转换成字节数组
            byte[] bytesKey = new byte[sProvider.KeySize / 8];
            //把向量转换成字节数组
            byte[] bytesIV = new byte[sProvider.IV.Length];
            for (int i = 0; i < bytesKey.Length; i++)
                bytesKey[i] = byKey[i % byKey.Length];
            for (int i = 0; i < bytesIV.Length; i++)
                bytesIV[i] = byKey[i % byKey.Length];
            MemoryStream outStream = new MemoryStream();
            CryptoStream cst = new CryptoStream(outStream, sProvider.CreateDecryptor(bytesKey, bytesIV), CryptoStreamMode.Write);
            cst.Write(inData, 0, inData.Length);
            cst.FlushFinalBlock();
            outData = outStream.ToArray();
            outStream.Close();
        }
        /// <summary>
        /// 生成一对Rsa公钥和私钥，公钥用于加密，私钥用于解密
        /// </summary>
        /// <returns>公钥，私钥</returns>
        public static KeyValuePair<string, string> GetRsaPrivateAndPublicKey()
        {
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            string public_Key = Convert.ToBase64String(RSA.ExportCspBlob(false));
            string private_Key = Convert.ToBase64String(RSA.ExportCspBlob(true));
            return new KeyValuePair<string, string>(public_Key, private_Key);
        }
        public static void RsaEncrypt(string publicKey, Stream inStream, Stream outStream)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.ImportCspBlob(Convert.FromBase64String(publicKey));
            var bufferSize = (rsa.KeySize / 8 - 11);
            byte[] buffer = new byte[bufferSize];
            int readLen;
            inStream.Position = 0; outStream.Position = 0;
            while ((readLen = inStream.Read(buffer, 0, bufferSize)) > 0)
            {
                byte[] dataToEnc = new byte[readLen];
                Array.Copy(buffer, 0, dataToEnc, 0, readLen);
                byte[] encData = rsa.Encrypt(dataToEnc, false);
                outStream.Write(encData, 0, encData.Length);
            }
            rsa.Clear();
        }
        public static void RsaEncrypt(string publicKey, byte[] inData, out byte[] outData)
        {
            MemoryStream inStream = new MemoryStream(inData);
            MemoryStream outStream = new MemoryStream();
            RsaEncrypt(publicKey, inStream, outStream);
            outData = outStream.ToArray();
        }
        public static void RsaDecrypt(string privateKey, Stream inStream, Stream outStream)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.ImportCspBlob(Convert.FromBase64String(privateKey));
            int keySize = rsa.KeySize / 8;
            byte[] buffer = new byte[keySize];
            int readLen;
            inStream.Position = 0; outStream.Position = 0;
            while ((readLen = inStream.Read(buffer, 0, keySize)) > 0)
            {
                byte[] dataToDec = new byte[readLen];
                Array.Copy(buffer, 0, dataToDec, 0, readLen);
                byte[] decData = rsa.Decrypt(dataToDec, false);
                outStream.Write(decData, 0, decData.Length);
            }
            rsa.Clear();
        }
        public static void RsaDecrypt(string privateKey, byte[] inData, out byte[] outData)
        {
            MemoryStream inStream = new MemoryStream(inData);
            MemoryStream outStream = new MemoryStream();
            RsaDecrypt(privateKey, inStream, outStream);
            outData = outStream.ToArray();
        }

        public enum HashKind { SHA, SHA1, MD5, SHA256, SHA384, SHA512, RSA }
        /// <summary>
        /// 哈希值获取
        /// </summary>
        /// <param name="kind">哈希算法名称</param>
        /// <param name="inStream">原始数据</param>
        /// <returns></returns>
        public static byte[] Hash(HashKind kind, string inString)
        {
            return Hash(kind, Encoding.Default.GetBytes(inString));
        }
        /// <summary>
        /// 哈希值获取
        /// </summary>
        /// <param name="kind">哈希算法名称</param>
        /// <param name="inStream">原始数据</param>
        /// <returns></returns>
        public static byte[] Hash(HashKind kind, Stream inStream)
        {
            HashAlgorithm hash;
            switch (kind)
            {
                case HashKind.SHA:
                    hash = HashAlgorithm.Create("SHA"); break;
                case HashKind.SHA1:
                    hash = HashAlgorithm.Create("SHA1"); break;
                case HashKind.MD5:
                    hash = HashAlgorithm.Create("MD5"); break;
                case HashKind.SHA256:
                    hash = HashAlgorithm.Create("SHA256"); break;
                case HashKind.SHA384:
                    hash = HashAlgorithm.Create("SHA384"); break;
                case HashKind.SHA512:
                    hash = HashAlgorithm.Create("SHA512"); break;
                case HashKind.RSA:
                    byte[] bytes = new byte[inStream.Length];
                    inStream.Read(bytes, 0, (int)inStream.Length);
                    return new RSACryptoServiceProvider(new CspParameters()).Encrypt(bytes, false);
                default:
                    hash = HashAlgorithm.Create("SHA"); break;
            }
            return hash.ComputeHash(inStream);
        }
        /// <summary>
        /// 哈希值获取
        /// </summary>
        /// <param name="kind">哈希算法名称</param>
        /// <param name="inData">原始数据</param>
        /// <returns></returns>
        public static byte[] Hash(HashKind kind, byte[] inData)
        {
            HashAlgorithm hash;
            switch (kind)
            {
                case HashKind.SHA:
                    hash = HashAlgorithm.Create("SHA"); break;
                case HashKind.SHA1:
                    hash = HashAlgorithm.Create("SHA1"); break;
                case HashKind.MD5:
                    hash = HashAlgorithm.Create("MD5"); break;
                case HashKind.SHA256:
                    hash = HashAlgorithm.Create("SHA256"); break;
                case HashKind.SHA384:
                    hash = HashAlgorithm.Create("SHA384"); break;
                case HashKind.SHA512:
                    hash = HashAlgorithm.Create("SHA512"); break;
                default:
                    hash = HashAlgorithm.Create("SHA"); break;
            }
            return hash.ComputeHash(inData);
        }
        /// <summary>
        /// 哈希值获取
        /// </summary>
        /// <param name="kind">哈希算法名称</param>
        /// <param name="inStream">原始数据</param>
        /// <returns></returns>
        public static string Hashto(HashKind kind, string inString)
        {
            return Hashto(kind, Encoding.Default.GetBytes(inString));
        }
        /// <summary>
        /// 哈希值获取
        /// </summary>
        /// <param name="kind">哈希算法名称</param>
        /// <param name="inStream">原始数据</param>
        /// <returns></returns>
        public static string Hashto(HashKind kind, Stream inStream)
        {
            HashAlgorithm hash;
            switch (kind)
            {
                case HashKind.SHA:
                    hash = HashAlgorithm.Create("SHA"); break;
                case HashKind.SHA1:
                    hash = HashAlgorithm.Create("SHA1"); break;
                case HashKind.MD5:
                    hash = HashAlgorithm.Create("MD5"); break;
                case HashKind.SHA256:
                    hash = HashAlgorithm.Create("SHA256"); break;
                case HashKind.SHA384:
                    hash = HashAlgorithm.Create("SHA384"); break;
                case HashKind.SHA512:
                    hash = HashAlgorithm.Create("SHA512"); break;
                case HashKind.RSA:
                    byte[] bytes = new byte[inStream.Length];
                    inStream.Read(bytes, 0, (int)inStream.Length);
                    var encryptBytes = new RSACryptoServiceProvider(new CspParameters()).Encrypt(bytes, false);
                    return Convert.ToBase64String(encryptBytes);
                default:
                    hash = HashAlgorithm.Create("SHA"); break;
            }
            var encryptbytes = hash.ComputeHash(inStream);
            return Convert.ToBase64String(encryptbytes);
        }
        /// <summary>
        /// 哈希值获取
        /// </summary>
        /// <param name="kind">哈希算法名称</param>
        /// <param name="inData">原始数据</param>
        /// <returns></returns>
        public static string Hashto(HashKind kind, byte[] inData)
        {
            HashAlgorithm hash;
            switch (kind)
            {
                case HashKind.SHA:
                    hash = HashAlgorithm.Create("SHA"); break;
                case HashKind.SHA1:
                    hash = HashAlgorithm.Create("SHA1"); break;
                case HashKind.MD5:
                    hash = HashAlgorithm.Create("MD5"); break;
                case HashKind.SHA256:
                    hash = HashAlgorithm.Create("SHA256"); break;
                case HashKind.SHA384:
                    hash = HashAlgorithm.Create("SHA384"); break;
                case HashKind.SHA512:
                    hash = HashAlgorithm.Create("SHA512"); break;
                default:
                    hash = HashAlgorithm.Create("SHA"); break;
            }
            var encryptbytes = hash.ComputeHash(inData);
            return Convert.ToBase64String(encryptbytes);
        }
        /// <summary>
        /// 哈希值获取
        /// </summary>
        /// <param name="kind">哈希算法名称</param>
        /// <param name="inStream">原始数据</param>
        /// <returns></returns>
        public static string HashValue(HashKind kind, string inString)
        {
            return HashValue(kind, Encoding.Default.GetBytes(inString));
        }
        /// <summary>
        /// 哈希值获取
        /// </summary>
        /// <param name="kind">哈希算法名称</param>
        /// <param name="inData">原始数据</param>
        /// <returns></returns>
        public static string HashValue(HashKind kind, byte[] inData)
        {
            HashAlgorithm hash;
            switch (kind)
            {
                case HashKind.SHA:
                    hash = HashAlgorithm.Create("SHA"); break;
                case HashKind.SHA1:
                    hash = HashAlgorithm.Create("SHA1"); break;
                case HashKind.MD5:
                    hash = HashAlgorithm.Create("MD5"); break;
                case HashKind.SHA256:
                    hash = HashAlgorithm.Create("SHA256"); break;
                case HashKind.SHA384:
                    hash = HashAlgorithm.Create("SHA384"); break;
                case HashKind.SHA512:
                    hash = HashAlgorithm.Create("SHA512"); break;
                default:
                    hash = HashAlgorithm.Create("SHA"); break;
            }
            var encryptbytes = hash.ComputeHash(inData);
            string x = "";
            foreach (byte b in encryptbytes) x += b.ToString("x2");
            return x;
        }
    }
}
